"""
Copyright (c) 2022 Huawei Technologies Co.,Ltd.

openGauss is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:

          http://license.coscl.org.cn/MulanPSL2

THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
"""
"""
Case Type   : 工具--gs_probackup
Case Name   : 单表超过1G时，本地增量备份
Create At   : 2021/08/17
@zou_jialiang0505328126
Description :
    1.打开增量备份开关
    2.给普通用户设置replication
    3. 创建单表大于1GB
    4.初始化数据目录
    5.添加备份实例
    6.全量备份
    7.更新数据
    8.增量备份1
    9.ddl: create tablespace
    10.增量备份2 （创建表空间的，备份的时候一定要带上--external-dirs 参数）
    11. 停止集群
    12. 增量恢复到第1次增备
    13.查看数据一致性
    14.停止集群
    15. 增量恢复到第2次增备
    16.查看数据一致性
Expect      :
    1.成功
    2.成功
    3.单表大于1GB
    4.成功
    5.成功
    6.成功
    7.更新成功
    8.成功
    9.成功
    10.成功
    11.成功
    12.成功
    13.成功
    14.成功
    15.成功
    16.成功
History     :
"""

import unittest
import os
from yat.test import Node, macro
from testcase.utils.Common import Common
from testcase.utils.Constant import Constant
from testcase.utils.CommonSH import CommonSH
from testcase.utils.CommonSH import RestartDbCluster
from testcase.utils.Logger import Logger


class Probackup(unittest.TestCase):
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info(
            '--Opengauss_Reliability_Tools_Probackup_Case001:开始执行--')
        self.primary_root_node = Node(node='PrimaryRoot')
        self.pri_dbuser = Node(node='PrimaryDbUser')
        self.sta1_dbuser = Node(node='Standby1DbUser')
        self.com = Common()
        self.constant = Constant()
        self.primary_sh = CommonSH('PrimaryDbUser')
        self.sta1_sh = CommonSH('Standby1DbUser')
        self.sta2_sh = CommonSH('Standby2DbUser')
        self.pg_hba_path = os.path.join(
            macro.DB_INSTANCE_PATH, macro.PG_HBA_FILE_NAME)
        self.conf_path = os.path.join(
            macro.DB_INSTANCE_PATH, macro.DB_PG_CONFIG_NAME)
        self.tb_name = "t_opengauss_reliability_tools_probackup001_01"
        self.tb_name1 = "t_opengauss_reliability_tools_probackup_001_02"
        self.tbspc_name = "ts_opengauss_reliability_tools_probackup_001"
        self.parent_path = os.path.dirname(macro.DB_INSTANCE_PATH)
        self.backup_path = os.path.join(self.parent_path, 'probackup')
        self.ts_path = os.path.join(self.parent_path, self.tbspc_name)
        self.probackup_instance_name = "probackup1"

    def test_main(self):
        self.log.info("------------1.打开增量备份开关----------------")
        text = '----step1:打开增量备份开关 expect:成功----'
        shell_cmd = f"cp {self.conf_path} {self.conf_path}_testbak"
        self.log.info(shell_cmd)
        result = self.pri_dbuser.sh(shell_cmd).result()
        self.log.info(result)
        shell_cmd = f"echo 'enable_cbm_tracking = on'>>{self.conf_path}"
        self.log.info(shell_cmd)
        result = self.pri_dbuser.sh(shell_cmd).result()
        self.log.info(result)
        result = self.primary_sh.stopDbCluster()
        self.assertTrue(result, '执行失败:' + text)
        result = self.primary_sh.startDbCluster()
        self.assertTrue(result, '执行失败:' + text)
        sql = "show enable_cbm_tracking"
        result = self.primary_sh.executDbSql(sql)
        self.log.info(result)
        self.assertIn("on", result.strip().splitlines()[-2], '执行失败:' + text)

        text = '----step2:给普通用户设置replication expect:成功----'
        self.log.info(text)
        shell_cmd = f"cp {self.pg_hba_path} {self.pg_hba_path}_testbak"
        self.log.info(shell_cmd)
        result = self.pri_dbuser.sh(shell_cmd).result()
        self.log.info(result)
        shell_cmd = f"echo 'host  replication  {self.pri_dbuser.db_user} " \
            f"{self.pri_dbuser.ssh_host}/32  " \
            f"sha256'>>{self.pg_hba_path};" \
            f"echo 'host  replication  {self.sta1_dbuser.db_user} " \
            f"{self.sta1_dbuser.ssh_host}/32  " \
            f"sha256'>>{self.pg_hba_path};" \
            f"cat {self.pg_hba_path}| " \
            f"grep 'host  replication  {self.pri_dbuser.db_user}'"
        self.log.info(shell_cmd)
        result = self.pri_dbuser.sh(shell_cmd).result()
        self.log.info(result)
        self.assertIn(self.sta1_dbuser.ssh_host, result,  '执行失败:' + text)

        self.log.info("--------------3.创建单表大于1GB-------------")
        text = '----step3:创建单表大于1GB expect:成功----'
        sql = f"drop table if exists {self.tb_name};" \
            f"create table {self.tb_name}(i int, c varchar(100))"
        result = self.primary_sh.executDbSql(sql)
        self.log.info(result)
        self.assertIn(self.constant.TABLE_CREATE_SUCCESS, result,
                      '执行失败:' + text)
        sql = f"insert into {self.tb_name} values" \
            f"(generate_series(1,999999), " \
            f"'test-11111999****------====^^" \
            f"&&&&&3333gggggggggggggggggggggggggggggggggddddddddddddddd')"
        for i in range(9):
            result = self.primary_sh.executDbSql(sql)
            self.log.info(result)
            self.assertIn("INSERT", result, '执行失败:' + text)

        self.log.info("--------4.初始化数据目录---------------")
        text = '----step4:初始化数据目录 expect:成功----'
        cmd = f"source {macro.DB_ENV_PATH};gs_probackup " \
            f"init -B {self.backup_path}"
        self.log.info(cmd)
        result = self.pri_dbuser.sh(cmd).result()
        self.log.info(result)
        self.assertIn("successfully inited", result, '执行失败:' + text)

        self.log.info("-----------5.添加备份实例--------------")
        text = '----step5:添加备份实例 expect:成功----'
        cmd = f"source {macro.DB_ENV_PATH};" \
            f"gs_probackup add-instance -B {self.backup_path} " \
            f"--instance={self.probackup_instance_name} -D " \
            f"{macro.DB_INSTANCE_PATH}"
        self.log.info(cmd)
        result = self.pri_dbuser.sh(cmd).result()
        self.log.info(result)
        self.assertIn("successfully inited", result, '执行失败:' + text)

        self.log.info("-----------6.全量备份--------------")
        text = '----step6:全量备份 expect:成功----'
        cmd = f"source {macro.DB_ENV_PATH};" \
            f"gs_probackup backup -B {self.backup_path} -b FULL " \
            f"--instance={self.probackup_instance_name} " \
            f"-d {self.pri_dbuser.db_name} -p {self.pri_dbuser.db_port} " \
            f"-U {self.pri_dbuser.db_user} -W {self.pri_dbuser.db_password}"
        self.log.info(cmd)
        result = self.pri_dbuser.sh(cmd).result()
        self.log.info(result)
        self.assertIn("completed", result, '执行失败:' + text)

        self.log.info("----------7.更新数据--------------")
        text = '----step7:更新数据 expect:成功----'
        sql = f"update {self.tb_name} set c='update' where i<99"
        result = self.primary_sh.executDbSql(sql)
        self.log.info(result)
        self.assertIn("UPDATE", result, '执行失败:' + text)

        self.log.info("-----------8.增量备份1--------------")
        text = '----step8:增量备份1 expect:成功----'
        cmd = f"source {macro.DB_ENV_PATH};" \
            f"gs_probackup backup -B {self.backup_path} -b PTRACK " \
            f"--instance={self.probackup_instance_name} " \
            f"-d {self.pri_dbuser.db_name} -p {self.pri_dbuser.db_port} " \
            f"-U {self.pri_dbuser.db_user} -W {self.pri_dbuser.db_password}"
        self.log.info(cmd)
        result = self.pri_dbuser.sh(cmd).result()
        self.log.info(result)
        self.assertIn("completed", result, '执行失败:' + text)

        self.log.info("----------9.ddl: create tablespace--------------")
        text = '----step9:ddl: create tablespace expect:成功----'
        sql = f"create tablespace {self.tbspc_name} owner " \
            f"{self.pri_dbuser.db_user} location '{self.ts_path}';" \
            f"create table {self.tb_name1}(a int) " \
            f"tablespace {self.tbspc_name};" \
            f"insert into {self.tb_name1} values (8);" \
            f"select reltablespace from pg_class " \
            f"where relname='{self.tb_name1}';"
        result = self.primary_sh.executDbSql(sql)
        self.log.info(result)
        self.assertIn("CREATE", result, '执行失败:' + text)

        self.log.info("-----------10.增量备份2--------------")
        text = '----step10:增量备份2 expect:成功----'
        cmd = f"source {macro.DB_ENV_PATH};" \
            f"gs_probackup backup -B {self.backup_path} -b PTRACK " \
            f"--instance={self.probackup_instance_name} " \
            f"-d {self.pri_dbuser.db_name} -p {self.pri_dbuser.db_port} " \
            f"-U {self.pri_dbuser.db_user} -W {self.pri_dbuser.db_password} " \
            f"--external-dirs={self.ts_path}"
        self.log.info(cmd)
        result = self.pri_dbuser.sh(cmd).result()
        self.log.info(result)
        self.assertIn("completed", result, '执行失败:' + text)

        self.log.info("--------------11.停止集群-------------")
        text = '----step11:停止集群 expect:成功----'
        result = self.primary_sh.stopDbCluster()
        self.assertTrue(result, '执行失败:' + text)

        self.log.info("-----------12.增量恢复到第1次增备--------------")
        text = '----step12:增量恢复到第1次增备 expect:成功----'
        cmd = f"source {macro.DB_ENV_PATH};" \
            f"gs_probackup show -B  {self.backup_path} " \
            f"--instance={self.probackup_instance_name}"
        self.log.info(cmd)
        result = self.pri_dbuser.sh(cmd).result()
        self.log.info(result)
        backup_id = result.splitlines()[-2].split()[2].strip()
        self.log.info(backup_id)
        cmd = f"source {macro.DB_ENV_PATH};" \
            f"gs_probackup restore -B {self.backup_path} " \
            f"-i {backup_id} --instance={self.probackup_instance_name} " \
            f"--incremental-mode=checksum"
        self.log.info(cmd)
        result = self.pri_dbuser.sh(cmd).result()
        self.log.info(result)
        self.assertIn("completed", result, '执行失败:' + text)
        result = self.primary_sh.startDbCluster()
        self.assertFalse(result, '执行失败:' + text)
        result = self.sta1_sh.buildStandby()
        self.log.info(result)
        self.assertIn(self.constant.BUILD_SUCCESS_MSG, result, '执行失败:' + text)
        result = self.sta2_sh.buildStandby()
        self.log.info(result)
        self.assertIn(self.constant.BUILD_SUCCESS_MSG, result, '执行失败:' + text)

        self.log.info("-----------13.查看数据一致性--------------")
        text = '----step13:查看数据一致性 expect:成功----'
        result = self.primary_sh.executDbSql(f"\d")
        self.log.info(result)
        self.assertNotIn(self.tb_name1, result, '执行失败:' + text)
        result = self.primary_sh.executDbSql(f"\db")
        self.log.info(result)
        self.assertNotIn(self.tbspc_name, result, '执行失败:' + text)
        result = self.primary_sh.executDbSql(
            f"select count(*) from {self.tb_name} where c='update';")
        self.log.info(result)
        self.assertIn("882", result, '执行失败:' + text)

        self.log.info("--------------14.停止集群-------------")
        text = '----step14:停止集群 expect:成功----'
        result = self.primary_sh.stopDbCluster()
        self.assertTrue(result, '执行失败:' + text)

        self.log.info("-----------15.增量恢复到第2次增备--------------")
        text = '----step15:增量恢复到第2次增备 expect:成功----'
        cmd = f"source {macro.DB_ENV_PATH};" \
            f"gs_probackup show -B  {self.backup_path} " \
            f"--instance={self.probackup_instance_name}"
        self.log.info(cmd)
        result = self.pri_dbuser.sh(cmd).result()
        self.log.info(result)
        backup_id = result.splitlines()[-3].split()[2].strip()
        self.log.info(backup_id)
        cmd = f"source {macro.DB_ENV_PATH};" \
            f"gs_probackup restore -B {self.backup_path} " \
            f"-i {backup_id} --instance={self.probackup_instance_name} " \
            f"--incremental-mode=checksum"
        self.log.info(cmd)
        result = self.pri_dbuser.sh(cmd).result()
        self.log.info(result)
        self.assertIn("completed", result, '执行失败:' + text)
        result = self.primary_sh.startDbCluster()
        self.assertFalse(result, '执行失败:' + text)
        result = self.sta1_sh.buildStandby()
        self.log.info(result)
        self.assertIn(self.constant.BUILD_SUCCESS_MSG, result, '执行失败:' + text)
        result = self.sta2_sh.buildStandby()
        self.log.info(result)
        self.assertIn(self.constant.BUILD_SUCCESS_MSG, result, '执行失败:' + text)

        self.log.info("-----------16.查看数据一致性--------------")
        text = '----step16:查看数据一致性 expect:成功----'
        sql = f"\db"
        result = self.primary_sh.executDbSql(sql)
        self.log.info(result)
        self.assertIn(self.tbspc_name, result, '执行失败:' + text)
        sql = f"select count(*) from {self.tb_name} where c='update';" \
            f"select count(*) from {self.tb_name1};"
        result = self.primary_sh.executDbSql(sql)
        self.log.info(result)
        self.assertIn("882", result, '执行失败:' + text)

    def tearDown(self):
        self.log.info('--------------还原配置文件-------------')
        shell_cmd = f"rm -rf {self.conf_path};" \
            f"mv {self.conf_path}_testbak {self.conf_path};" \
            f"rm -rf {self.pg_hba_path};" \
            f"mv {self.pg_hba_path}_testbak {self.pg_hba_path};"
        self.log.info(shell_cmd)
        result = self.pri_dbuser.sh(shell_cmd).result()
        self.log.info(result)
        result = self.primary_sh.stopDbCluster()
        self.log.info(result)
        result = self.primary_sh.startDbCluster()
        self.log.info(result)
        self.log.info("-----------删除表-----------")
        sql = f"drop table if exists {self.tb_name};" \
            f"drop table if exists {self.tb_name1};" \
            f"drop tablespace if exists {self.tbspc_name}"
        result = self.primary_sh.executDbSql(sql)
        self.log.info(result)
        self.log.info("-----------删除备份文件-----------------")
        shell_cmd = f"rm -rf {self.backup_path};rm -rf {self.ts_path}"
        self.log.info(shell_cmd)
        result = self.pri_dbuser.sh(shell_cmd).result()
        self.log.info(result)
        self.log.info('--Opengauss_Reliability_Tools_Probackup_Case001:执行完成-')
